JS30 Day 26 筆記


Posted by GL on 2023-05-23

目標

做一個隨著滑鼠移動展開下拉選單的導覽列

Demo

step 1 : 取得 HTML 頁面元素,并且建立監聽事件

// 取得導覽列 nav bar 中的每一個選項
const triggers = document.querySelectorAll('.cool > li');
// 取得下拉選單的白色背景
const background  = document.querySelector('.dropdownBackground');
// 取得整個導覽列 nav bar
const nav  = document.querySelector('.top');

// 滑鼠移入事件
function handleEnter() {
  console.log('mouse in')
}

// 滑鼠移出事件
function handleLeave() {
  console.log('mouse out')
}

// 在導覽列每個選項監聽 mouseenter、mouseLeave 事件
triggers.forEach(trigger => trigger.addEventListener('mouseenter', handleEnter));
triggers.forEach(trigger => trigger.addEventListener('mouseleave', handleLeave));

step 2 : handleEnter function

function handleEnter() {
  console.log('mouse in')
  // 滑鼠指到的選項 li,增加 trigger-enter 的 css 樣式
  this.classList.add('trigger-enter');
  // 爲避免 trigger-enter-active 的樣式先於 trigger-enter 先出現
  // 當滑鼠移入 li 元素的選項時,先檢查是否有 trigger-enter className
  // 若有,才會在 150 ms 後新增 trigger-enter-active 這個 class name
  setTimeout(() => this.classList.contains('trigger-enter') && this.classList.add('trigger-enter-active'), 150);

  // 在白色背景增加 open 這個 class,讓 opacity 顯示為 1
  background.classList.add('open');

  // 取得滑鼠滑入的 li 元素選項下方的 dropdown
  const dropdown = this.querySelector('.dropdown');
  // 取得這個 dropdown 的大小以及位置等資訊
  const dropdownCoords = dropdown.getBoundingClientRect();
  // 取得 nav 的大小以及位置等資訊
  const navCoords = nav.getBoundingClientRect();

  // coords 物件儲存白色背景根據下拉選單的大小與位置,做相應的位移
  const coords =
    {
      height: dropdownCoords.height,
      width: dropdownCoords.width,
      // 出現上方因 nav 的出現而增加的唯一,因此減去 nav 的位置
      top: dropdownCoords.top - navCoords.top,
      left: dropdownCoords.left - navCoords.left
    };

  // CSS style 設定白色背景的大小和位置
  background.style.setProperty('width', `${coords.width}px`);
  background.style.setProperty('height', `${coords.height}px`);
  background.style.setProperty('transform', `translate(${coords.left}px, ${coords.top}px)`);
}

step 3 : handleLeave function

function handleLeave(){
  console.log('mouse out')
  // 移除在 mouseenter 被加上的 class 樣式
  this.classList.remove('trigger-enter','trigger-enter-active')
  background.classList.remove('open')
}

補充

  1. 讓元素從畫面消失的方法:
    display:none : 呈現時看不出有該元素的存在
    visibility:hidden: 看不出有該元素的存在,但保留元素原本的位置與大小
  2. opacity 表示元素的透明度,數值為 0 ~ 1,數字越小越透明。
  3. 這次的範例中利用 js 控制 css 的 class 樣式的開關,進而控制元素是否顯示
.dropdown {
  /* 下拉選單原本的 opacity:0,display: none; */
  opacity: 0;
  position: absolute;
  overflow: hidden;
  padding: 20px;
  top: -20px;
  border-radius: 2px;
  transition: all 0.5s;
  transform: translateY(100px);
  will-change: opacity;
  display: none;
}

/* 加了 trigger-enter 之後 display: block,
 * getBoundingClientRect() 可以計算變成 block 後大小與位置 */
.trigger-enter .dropdown {
  display: block;
}

/* 加了 trigger-enter-active class 之後 opacity 為 1 */
.trigger-enter-active .dropdown {
  opacity: 1;
}

.dropdownBackground {
  width: 100px;
  height: 100px;
  position: absolute;
  background: #fff;
  border-radius: 4px;
  box-shadow: 0 50px 100px rgba(50, 50, 93, .1), 0 15px 35px rgba(50, 50, 93, .15), 0 5px 15px rgba(0, 0, 0, .1);
  transition: all 0.3s, opacity 0.1s, transform 0.2s;
  transform-origin: 50% 0;
  display: flex;
  justify-content: center;
  /* 下拉選單白色背景原本的 opacity 為 0 */
  opacity: 0;
}

/* 加了 open class 之後 opacity 為 1 */
.dropdownBackground.open {
  opacity: 1;
}

參考資料:


#JS 30







Related Posts

Node.js Advanced Interview Questions for Experienced Professionals

Node.js Advanced Interview Questions for Experienced Professionals

CS50 Hash Table

CS50 Hash Table

簡明 Python Pandas 入門教學

簡明 Python Pandas 入門教學


Comments